struct Point {
    x: f64,
    y: f64,
}
// 实现代码块,'Point'的所有方法都在这里实现
impl Point {
    // 这是一个静态方法(static method)
    // 静态方法不需要被实例调用,通过::调用,如Point::origin()
    // 这类方法一般用作构造器(constructor)
    fn origin() -> Self {
        Self {x: 0.0, y: 0.0}
    }
    // 需要参数的静态方法
    fn new(x: f64, y: f64) -> Point {
        Self {x, y}
        // Self {x: x, y: y} //上面是个简写
    }
}
struct Rectangle {
    p1: Point,
    p2: Point,
}
impl Rectangle {
    // 这是一个实例方法(instance method)
    // '&self' 是'self: &Self'的语法糖(sugar),其中'Self'是方法调用者的
    // 类型。在这个例子中'Self' = 'Rectangle'
    fn area(&self) -> f64 {
        // 'self'通过点运算符来访问结构体字段
        let Point{x: x1, y: y1} = self.p1;
        let Point{x: x2, y: y2} = self.p2;
        // 'abs'是一个'f64'类型的方法,返回调用者的绝对值
        ((x1 - x2) * (y1 - y2)).abs()
    }
    // 求周长
    fn perimeter(&self) -> f64 {
        let Point {x: x1, y: y1} = self.p1;
        let Point {x: x2, y: y2} = self.p2;

        2.0 * ((x1 - x2).abs() + (y1 - y2).abs())
    }
    // 这个方法要求调用者是可变的,修改长方形边长
    // '&mut self'为'self: &mut Self'的语法糖
    fn translate(&mut self, p: Point) {
        self.p1.x += p.x;
        self.p2.x += p.x;

        self.p1.y += p.y;
        self.p2.y += p.y;

    }
}

// 'Pair'拥有资源:两个堆分配的整型
struct Pair(Box<i32>, Box<i32>);

impl Pair {
    // // 这个方法会“消耗”调用者的资源
    // 'self' 为 'self: Self'的语法糖
    fn destroy(self) {
        // 解构'self'
        let Pair(first, second) = self;
        println!("Destroying Pair({first}, {second})");
        // 'first' 和 'second'离开作用域后会被释放
    }
}

fn main() {
    let rectangle = Rectangle {
        // 静态方法使用双冒号调用
        p1: Point::origin(),
        p2: Point::new(3.0, 4.0),
    };
    // 实例方法通过点运算符调用
    // 注意第一个参数是 '&self'是隐式传递的,亦即:
    // 'rectangle.perimeter()' === 'Rectangle::perimeter(&rectangle)'
    println!("Rectangle perimeter: {}", rectangle.perimeter());
    println!("Rectangle area: {}", rectangle.area());

    let mut square = Rectangle {
        p1: Point::origin(),
        p2: Point::new(1.0, 1.0),
    };
    let p = Point::new(1.0, 1.0);
    // rectangle.translate(p); // 错误: rectangle是不可变的
    square.translate(p);
    println!("Square p1: ({}, {}), p2: ({}, {})", square.p1.x, square.p1.y, square.p2.x, square.p2.y);

    let pair = Pair(Box::new(3), Box::new(4));
    pair.destroy();
    // 错误: 调用者已经被销毁
    // pair.destroy();
    //试试把上面的注释去掉
}
